import Plugin from "../../lib/plugins/plugin.js"
import Bott from "./lib/Bott.js"
import { exec, execSync } from "child_process"
import yaml from "yaml"
import fs from "node:fs"
import path from "node:path"


// 读取名称，版本，作者
const { name, version, author } = JSON.parse(fs.readFileSync("plugins/QQGuild-Plugin/package.json", "utf8"))

// 全局配置
global.__QQGuild__ = {
  Init: undefined,
  ErrorFile: "plugins/QQGuild-Plugin/error.log",
  Name: name,
  Version: version,
  Author: author
}

export class QQGuild extends Plugin {
  constructor() {
    super({
      name: "QQ频道插件",
      priority: -99999999999999999,
      rule: [
        {
          reg: "^#频道插件\\.",
          fnc: "控制台",
          permission: "master"
        }
      ]
    })
  }

  async 控制台(e) {
    if (global.__QQGuild__.Init !== true) {
      await e.reply("出现未知错误！")
      logger.error("警告！警告！警告！出现未知错误！")
      return
    }

    let cmd = e.msg.replace(/\s+/g, " ").trim().split(" ")

    switch (cmd.shift()) {
      case "#频道插件.机器人.添加":
        await e.reply(addBott(cmd))
        break
      case "#频道插件.机器人.删除":
        await e.reply(delBott(parseInt(cmd[0]), cmd[0] === "全部"))
        break
      case "#频道插件.机器人.启动":
        await e.reply(startBott(parseInt(cmd[0]), cmd[0] === "全部"))
        break
      case "#频道插件.机器人.停止":
        await e.reply(stopBott(parseInt(cmd[0]), cmd[0] === "全部"))
        break
      case "#频道插件.机器人.重连":
        reStartBott(parseInt(cmd[0]), cmd[0] === "全部")
        await e.reply("正在重连...")
        break
      case "#频道插件.机器人.状态":
        await e.reply(getBottState(parseInt(cmd[0])))
        break
      case "#频道插件.机器人.列表":
        await e.reply(getBottStateList())
        break
      case "#频道插件.机器人.设置":
        await e.reply(setBott(parseInt(cmd.shift()), cmd.shift(), cmd, e))
        break
      case "#频道插件.机器人.错误日志":
        await e.reply(await getErrMsg(parseInt(cmd[0]), cmd[0] === "全部", cmd[1], e))
        break
      case "#频道插件.帮助": case "#频道插件.机器人.帮助":
        let ret = [
          "#频道插件.机器人.添加\nAPPID\nTOKEN\nSANDBOX\nALLMSG\nAUTOSTART\nERRORECHO\nTOQRCODE",
          "#频道插件.机器人.删除 标号",
          "#频道插件.机器人.删除 全部",
          "#频道插件.机器人.启动 标号",
          "#频道插件.机器人.启动 全部",
          "#频道插件.机器人.停止 标号",
          "#频道插件.机器人.停止 全部",
          "#频道插件.机器人.重连 标号",
          "#频道插件.机器人.重连 全部",
          "#频道插件.机器人.状态 标号",
          "#频道插件.机器人.列表",
          "#频道插件.机器人.设置 标号 查看",
          "#频道插件.机器人.设置 标号 沙盒测试 开启/关闭",
          "#频道插件.机器人.设置 标号 全部消息 开启/关闭",
          "#频道插件.机器人.设置 标号 直接启动 开启/关闭",
          "#频道插件.机器人.设置 标号 错误回显 开启/关闭",
          "#频道插件.机器人.设置 标号 链接转换 开启/关闭/正则表达式",
          "#频道插件.机器人.错误日志 标号",
          "#频道插件.机器人.错误日志 全部",
          "#频道插件.机器人.错误日志 标号 清空",
          "#频道插件.机器人.错误日志 全部 清空",
          "#频道插件.帮助 #频道插件.机器人.帮助"
        ]
        if (e?.guild_id || e.user_id == "stdin") await e.reply(ret.join("\n"))
        else {
          let ret2 = ret
          ret = []
          ret2.map((v) => {
            let nickname
            if (v.includes("\n")) nickname = v.split("\n")[0]
            else nickname = v.split(" ")[0]
            ret.push({ message: v, user_id: Bot.uin, nickname: nickname })
          })
          await e.reply(await makeForwardMsg(e, `#频道插件.帮助\n版本 V${version}`, ret))
        }
        break
      case "#频道插件.更新日志":
        let cm = `cd plugins/QQGuild-Plugin/ && git log -100 --oneline --pretty=format:"%h||[%cd]  %s" --date=format:"%m-%d %H:%M"`
        let logAll
        try {
          logAll = await execSync(cm, { encoding: 'utf-8' })
        } catch (error) {
          logger.error(error.toString())
          await e.reply(error.toString())
        }
        if (!logAll) return false
        logAll = logAll.split('\n')
        let log = []
        for (let str of logAll) {
          str = str.split('||')
          log.push(str[1])
        }
        let line = log.length
        if (line <= 5 || e?.guild_id || e.user_id == "stdin"){
          log.unshift(`QQGuild-Plugin更新日志，共${line}条`)
          await e.reply(log.join("\n"))
        }
        else await e.reply(await makeForwardMsg(e, `QQGuild-Plugin更新日志，共${line}条`, log.join("\n\n")))
        break
      default:
        await e.reply("暂不支持此命令，请查看帮助.")
    }
  }
}

async function getErrMsg(index, isAll, cmd, e) {
  let data = JSON.parse(fs.readFileSync(global.__QQGuild__.ErrorFile, "utf8"))
  let none = true
  for (const i of data ? Object.values(data) : []) if(i.length > 0) none = false
  if (!data || Object.keys(data).length == 0 || none) return "暂无日志."
  let ret = ["#频道插件.机器人.错误日志"]
  let type = 0
  if (isAll) {
    if (cmd == "清空") {
      fs.writeFileSync(global.__QQGuild__.ErrorFile, JSON.stringify({}, "", "    "), "utf8")
      return "已清空."
    }
    for (const i of Object.keys(data)) {
      ret.push(`- 账号 => ${i}`)
      let num = 1
      for (const i2 of data[i]) {
        ret.push(`  - 序号 => ${num}\n  ：${i2.join("\n  ：")}`)
        num ++
      }
    }
  } else {
    let bott = global.Bott.get(index)
    if (!bott || data[bott.appId].length == 0)
      return "标号无效！"
    if (cmd == "清空") {
      data[bott.appId] = []
      fs.writeFileSync(global.__QQGuild__.ErrorFile, JSON.stringify(data, "", "    "), "UTF-8")
      return "已清空."
    }
    let num = 1
    for (const i of data[bott.appId]) {
      ret.push(`- 序号 => ${num}\n：${i.join("\n：")}`)
      num ++
    }
    type = num
  }
  let z = 0
  for (const i of Object.values(data)) z += i.length
  if ((type || z) <= 6 || e.user_id == "stdin" || e?.guild_id) return ret.join("\n")
  else {
    let title = ret[0]
    ret.shift()
    let ret2 = ret
    ret = []
    ret2.map((v) => {
      let nickname
      if (v.includes("\n")) {
        for (const i of v.split("\n"))
          if(i.includes("账号")) {
            nickname = i
            break
          }
      } else if (v.includes("账号")) nickname = v
      ret.push({ message: v, user_id: Bot.uin, nickname: nickname })
    })
    return await makeForwardMsg(e, title, ret)
  }
}

function saveConfig(cfgPath, config) {
  fs.writeFileSync(cfgPath, yaml.stringify(config), "utf8")
}

function addBott(config) {
  if (!/^1\d{8}$/.test(config[0]))
    return "APPID 不正确！"
  if (!/^[0-9a-zA-Z]{32}$/.test(config[1]))
    return "TOKEN 不正确！"
  let cfg = {
    appId: config[0],
    token: config[1],
    sandBox: config[2] === "true",
    allMsg: config[3] === "true",
    autoStart: config[4] === "true",
    ErrorEcho: config[5] === "true",
    toQRCode: config[6] === "true"
  }
  let cfgPath = path.join(global.Bott.cfgDir, `${cfg.appId}.yaml`)
  saveConfig(cfgPath, cfg)
  cfg.file = cfgPath
  global.Bott.set(global.Bott.size + 1, new Bott(cfg))
  return "已添加."
}

function delBott(index, isAll) {
  if (isAll) {
    global.Bott.forEach((bott) => {
      bott.stop()
      fs.rmSync(bott.configFile)
    })
    global.Bott.clear()
  } else {
    let bott = global.Bott.get(index)
    if (!bott) return "标号无效！"
    bott.stop()
    fs.rmSync(bott.configFile)
    global.Bott.delete(index)
  }
  return "已删除."
}

function startBott(index, isAll) {
  if (isAll)
    global.Bott.forEach((bott) => bott.start())
  else {
    let bott = global.Bott.get(index)
    if (!bott) return "标号无效！"
    bott.start()
  }
  return "正在启动..."
}

function stopBott(index, isAll) {
  if (isAll)
    global.Bott.forEach((bott) => bott.stop())
  else {
    let bott = global.Bott.get(index)
    if (!bott) return "标号无效！"
    bott.stop()
  }
  return "正在停止..."
}

async function reStartBott(index, isAll) {
  stopBott(index, isAll)
  await new Promise((r) => setTimeout(r, 3000))
  startBott(index, isAll)
}

function getBottState(index) {
  let bott = global.Bott.get(index)
  if (!bott) return "标号无效！"
  return [
    "#频道插件.机器人.状态",
    `- 标号 => ${index}`,
    `：${bott.name}`,
    `：${bott.state}`
  ].join("\n")
}

function getBottStateList() {
  let text = "#频道插件.机器人.列表"
  if (global.Bott.size < 1) text += "\n- 无"
  else {
    global.Bott.forEach((bott, index) => {
      text += [
        `\n- 标号 => ${index}`,
        `：${bott.appId}`,
        `：${bott.name}`,
        `：${bott.state}`
      ].join("\n")
    })
  }
  return text
}

function setBott(index, cmd, args, e) {
  let bott = global.Bott.get(index)
  if (!bott) return "标号无效！"

  let save = async () => {
    delete bott.toQRCodeRegExp
    // 保存配置文件
    await saveConfig(bott.configFile, bott)
    // 自动重启
    await reStartBott(index, false)
  }

  switch (cmd) {
    case "查看":
      let info =  [
        "#频道插件.机器人.设置 查看",
        `- APPID：${bott.appId}`
      ]
      if (e?.friend)
        info.push(`- TOKEN：${bott.token}`)
      info.push(`- 沙盒测试：${bott.sandBox === true ? "已开启" : "已关闭"}`)
      info.push(`- 全部消息：${bott.allMsg === true ? "已开启" : "已关闭"}`)
      info.push(`- 直接启动：${bott.autoStart === true ? "已开启" : "已关闭"}`)
      info.push(`- 错误回显：${bott.ErrorEcho === true ? "已开启" : "已关闭"}`)
      info.push(`- 链接转换：${bott.toQRCode === true ? "已开启" : bott.toQRCode ? `自定义规则(${bott.toQRCode})` : "已关闭"}`)
      return info.join("\n")
    case "沙盒测试":
      switch (args[0]) {
        case "开启":
          bott.sandBox = true
          break
        case "关闭":
          bott.sandBox = false
          break
        default:
          return "开启/关闭？"
      }
      save()
      return "已设置. 正在自动重连."
    case "全部消息":
      switch (args[0]) {
        case "开启":
          bott.allMsg = true
          break
        case "关闭":
          bott.allMsg = false
          break
        default:
          return "开启/关闭？"
      }
      save()
      return "已设置. 正在自动重连.\n注意！！公域机器人必须设置为关闭."
    case "直接启动":
      switch (args[0]) {
        case "开启":
          bott.autoStart = true
          break
        case "关闭":
          bott.autoStart = false
          break
        default:
          return "开启/关闭？"
      }
      save()
      return "已设置. 重启生效."
    case "错误回显":
      switch (args[0]) {
        case "开启":
          bott.ErrorEcho = true
          break
        case "关闭":
          bott.ErrorEcho = false
          break
        default:
          return "开启/关闭？"
      }
      save()
      return "已设置. 正在自动重连."
    case "链接转换":
      let ret = false
      switch (args[0]) {
        case "开启":
          bott.toQRCode = true
          ret = "开启"
          break
        case "关闭":
          bott.toQRCode = false
          ret = "关闭"
          break
        default:
          bott.toQRCode = args[0]
          ret = args[0]
      }
      save()
      return `链接匹配规则已设置为：${ret}. 正在自动重连.`
    default:
      return `暂不支持此设置[${cmd}].`
  }

  return "已设置."
}

async function makeForwardMsg(e, title, msg, end) {
  let nickname = Bot.nickname || "匿名用户"
  if (e.isGroup && !nickname) {
    let info = await Bot.getGroupMemberInfo(e.group_id, Bot.uin)
    nickname = info.card ?? info.nickname
  }
  let userInfo = {
    user_id: Bot.uin,
    nickname
  }
  let forwardMsg = [{...userInfo, message: title}]
  if (msg[0]?.message && msg[0]?.user_id)
    forwardMsg.push(...msg)
  else
    forwardMsg.push({...userInfo, message: msg})

  if (end) {
    forwardMsg.push({
      ...userInfo,
      message: end
    })
  }

  /** 制作转发内容 */
  if (e.isGroup) forwardMsg = await e.group.makeForwardMsg(forwardMsg)
  else forwardMsg = await e.friend.makeForwardMsg(forwardMsg)

  /** 处理描述 */
  if (typeof (forwardMsg.data) === 'object') {
    let detail = forwardMsg.data?.meta?.detail
    if (detail) detail.news = [{ text: title }]
  } else {
    forwardMsg.data = forwardMsg.data
      .replace(/\n/g, '')
      .replace(/<title color="#777777" size="26">(.+?)<\/title>/g, '___')
      .replace(/___+/, `<title color="#777777" size="26">${title}</title>`)
  }

  return forwardMsg
}

if (global.__QQGuild__.Init === undefined) {
  global.__QQGuild__.Init = false

  logger.info(`------------------------`)
  logger.info(`- 欢迎使用QQ频道插件(${global.__QQGuild__.Name}) v${global.__QQGuild__.Version}`)
  logger.info(`- 本插件作者：${global.__QQGuild__.Author}`)
  logger.info(`- 正在初始化... ^_^`)

  global.Bott = new Map()
  global.Bott.cfgDir = "plugins/QQGuild-Plugin/config"

  let fes = fs.readdirSync(global.Bott.cfgDir, { withFileTypes: true })
    .filter((f) => f.isFile() && /^\d+\.yaml$/.test(f.name))

  logger.info("- 发现机器人配置", `[${fes.length}个]`)
  logger.info(`------------------------`)

  for (let cfg of fes) {
    let cfgP = path.join(global.Bott.cfgDir, cfg.name)
    let cfgY = fs.readFileSync(cfgP, "utf8")
    let cfgJ = { file: cfgP, ...yaml.parse(cfgY) }
    global.Bott.set(global.Bott.size + 1, new Bott(cfgJ))
  }

  if (!fs.existsSync(global.__QQGuild__.ErrorFile))
    fs.writeFileSync(global.__QQGuild__.ErrorFile, JSON.stringify({}, "", "    "), "utf8")

  global.__QQGuild__.Init = true
}
